#include "types.h"
#include "util_buffer.h"
#include "hal_uart.h"
#include "kernel.h"
#include "service_uart.h"
#include "../config/service_uart_config.h"


// *********************** DEFINITIONS *************************

#define UART_CONTROL(handle)		(*((service_uart_Control *) handle))

typedef struct {
	UartNumber uartNumber;
	BOOL opened;
	Buffer sendBuffer;
	U8 sendBufferData[UART_SEND_BUFFER_SIZE];
	Buffer receiveBuffer;
	U8 receiveBufferData[UART_RECEIVE_BUFFER_SIZE];
} service_uart_Control;

// ******************** GLOBAL VARIABLES ***********************

service_uart_Control uartControls[4/*DEBUG*/];

// *********************** PROTOTYPES **************************

void service_uart_rxInterruptHandler(void *args);
void service_uart_txInterruptHandler(void *args);

// *************************** BODY ****************************

////////////////////////////////////////////////////////////////
/// Obtain number of available ports						 ///
////////////////////////////////////////////////////////////////
U8 service_uart_getNumberOfAvailablePorts(void)
{
	return hal_uart_getNumberOfUarts();
}

////////////////////////////////////////////////////////////////
/// Obtain pointer to array of all available ports			 ///
////////////////////////////////////////////////////////////////
UartNumber *service_uart_getAvailablePorts(void)
{
	return (UartNumber *)hal_uart_getUarts();
}

////////////////////////////////////////////////////////////////
/// Init uart service										 ///
////////////////////////////////////////////////////////////////
void service_uart_init(void)
{
	U8 i;
	hal_uart_UartNumber *uarts = hal_uart_getUarts();

	for(i = 0; i < hal_uart_getNumberOfUarts(); i++)
	{
		uartControls[i].uartNumber = uarts[i];
		uartControls[i].opened = FALSE;
		util_buffer_init(&(uartControls[i].sendBuffer), sizeof(uartControls[i].sendBufferData), uartControls[i].sendBufferData);
		util_buffer_init(&(uartControls[i].receiveBuffer), sizeof(uartControls[i].receiveBufferData), uartControls[i].receiveBufferData);
		hal_uart_installDataTransmittedInterruptHandler(uartControls[i].uartNumber, service_uart_txInterruptHandler, &uartControls[i]);
		hal_uart_installDataReceivedInterruptHandler(uartControls[i].uartNumber, service_uart_rxInterruptHandler, &uartControls[i]);
	}
}

////////////////////////////////////////////////////////////////
/// Open uart port											 ///
////////////////////////////////////////////////////////////////
UartHandle service_uart_open(UartNumber uart)
{
	U8 i;
	UartHandle result = 0;
	hal_uart_UartNumber *uarts = hal_uart_getUarts();

	for(i = 0; i < hal_uart_getNumberOfUarts(); i++)
	{
		if((uarts[i] == uart)
			&& (uartControls[i].opened == FALSE))
		{
			uartControls[i].opened = TRUE;
			uartControls[i].receiveBuffer.size = 0;

			result = (UartHandle) &uartControls[i];
		}
	}

	return result;
}

////////////////////////////////////////////////////////////////
/// Close uart port											 ///
////////////////////////////////////////////////////////////////
BOOL service_uart_close(UartHandle handle)
{
	if(handle != 0)
	{
		UART_CONTROL(handle).opened = FALSE;
		return TRUE;
	}
	else
	{
		return FALSE;
	}
}

////////////////////////////////////////////////////////////////
/// Send one byte through uart port							 ///
////////////////////////////////////////////////////////////////
BOOL service_uart_sendByte(UartHandle handle, U8 byte)
{
	if(UART_CONTROL(handle).sendBuffer.size == 0)
	{
		hal_uart_sendByte(UART_CONTROL(handle).uartNumber, byte);
		return TRUE;
	}
	else if(UART_CONTROL(handle).sendBuffer.size < UART_CONTROL(handle).sendBuffer.length)
	{
		return util_buffer_insert(&(UART_CONTROL(handle).sendBuffer), byte);
	}
	else
	{
		return FALSE;
	}
}

////////////////////////////////////////////////////////////////
/// Receive one byte through uart port						 ///
////////////////////////////////////////////////////////////////
BOOL service_uart_receiveByte(UartHandle handle, U8 *byte)
{
	if(UART_CONTROL(handle).receiveBuffer.size > 0)
	{
		return util_buffer_remove(&(UART_CONTROL(handle).receiveBuffer), byte);
	}
	else
	{
		return FALSE;
	}
}

////////////////////////////////////////////////////////////////
/// Receiving byte interrupt handler						 ///
////////////////////////////////////////////////////////////////
void service_uart_rxInterruptHandler(void *args)
{
	U8 byte;
	service_uart_Control *uartControl = (service_uart_Control *) args;

	byte = hal_uart_receiveByte(uartControl->uartNumber);
	util_buffer_insert(&(uartControl->receiveBuffer), byte);
}

////////////////////////////////////////////////////////////////
/// Transmitting byte interrupt handler						 ///
////////////////////////////////////////////////////////////////
void service_uart_txInterruptHandler(void *args)
{
	service_uart_Control *uartControl = (service_uart_Control *) args;

	if(uartControl->sendBuffer.size > 0)
	{
		U8 byte;

		util_buffer_remove(&(uartControl->receiveBuffer), &byte);
		hal_uart_sendByte(uartControl->uartNumber, byte);
	}
}

